----------------------------------------------------------------------------------
-- NOP-00000, ADD-00001, ADDU-00010, SUB-00011, SUBU-00100, unused from 00101 to 01000
-- AND-01001, OR-01010, XOR-01011, NOR-01100, SLT-01101, 
-- SLL-01110, SRL-01111, SRA-10000, BEQ-10001, BNE-10010, SLA-10011
-- MULTU-10100, MULT-10101
-- DIVU -10110, DIV -10111
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity alu is
Port (	Clk			: in	STD_LOGIC;
		Control		: in	STD_LOGIC_VECTOR (5 downto 0);
		Operand1	: in	STD_LOGIC_VECTOR (31 downto 0);
		Operand2	: in	STD_LOGIC_VECTOR (31 downto 0);
		Result1		: out	STD_LOGIC_VECTOR (31 downto 0);
		Result2		: out	STD_LOGIC_VECTOR (31 downto 0);
		Debug		: out	STD_LOGIC_VECTOR (31 downto 0));
end alu;

architecture Behavioral of alu is

	constant OP_NOP   : STD_LOGIC_VECTOR :="000000";
	constant OP_RESET : STD_LOGIC_VECTOR :="111111";
	constant OP_ADD	: STD_LOGIC_VECTOR :="000001";
	constant OP_ADDU	: STD_LOGIC_VECTOR :="000010";
	constant OP_SUB	: STD_LOGIC_VECTOR :="000011";
	constant OP_SUBU	: STD_LOGIC_VECTOR :="000100";
	constant OP_AND	: STD_LOGIC_VECTOR :="001001";
	constant OP_OR		: STD_LOGIC_VECTOR :="001010";
	constant OP_XOR 	: STD_LOGIC_VECTOR :="001011";
	constant OP_NOR 	: STD_LOGIC_VECTOR :="001100";
	constant OP_SLL 	: STD_LOGIC_VECTOR :="001110";
	constant OP_SRL 	: STD_LOGIC_VECTOR :="001111";
	constant OP_SRA 	: STD_LOGIC_VECTOR :="010000";
	constant OP_SLA 	: STD_LOGIC_VECTOR :="010011";
	constant OP_BEQ	: STD_LOGIC_VECTOR :="010001";
	constant OP_BNE 	: STD_LOGIC_VECTOR :="010010";
	constant OP_SLT 	: STD_LOGIC_VECTOR :="001101";
	constant OP_MULT	: STD_LOGIC_VECTOR :="010101";
	constant OP_MULTU : STD_LOGIC_VECTOR :="010100";
	constant OP_DIV 	: STD_LOGIC_VECTOR :="010111";
	constant OP_DIVU 	: STD_LOGIC_VECTOR :="010110";
	
	component internalALU is
    Port ( input1 : in  STD_LOGIC_VECTOR (31 downto 0);
           input2 : in  STD_LOGIC_VECTOR (31 downto 0);
           output : out  STD_LOGIC_VECTOR (31 downto 0);
           opcode : in  STD_LOGIC_VECTOR (4 downto 0);
           cout : out  STD_LOGIC);
	end component;
	
	component MULT_DIV is
	 Port ( a : in  STD_LOGIC_VECTOR (31 downto 0);
           m : in  STD_LOGIC_VECTOR (31 downto 0);
			  mul_div : STD_LOGIC;
			  sign_unsigned : STD_LOGIC;
			  clk : STD_LOGIC;
			  reset : STD_LOGIC;
           Ph : inout  STD_LOGIC_VECTOR (31 downto 0);
			  Pl : inout STD_LOGIC_VECTOR (31 downto 0);
           done : out  STD_LOGIC);
	end component;

	signal mux_output : STD_LOGIC_VECTOR (1 downto 0);
	signal logic_output : STD_LOGIC_VECTOR (31 downto 0);
	signal mul_div_high : STD_LOGIC_VECTOR (31 downto 0);
	signal mul_div_low : STD_LOGIC_VECTOR (31 downto 0);
	signal cout : STD_LOGIC;
	signal reset : STD_LOGIC;
	signal done : STD_LOGIC;
begin
	
	ALU_LOGIC : internalALU port map(operand1, operand2, logic_output, control(4 downto 0), cout);
	--MUL_DIV : MULT_DIV port map(operand2, operand1, control(1), control(0), clk, reset, mul_div_high, mul_div_low, done);
	process (Clk)
	begin  
		if (Clk'event and Clk = '1') then
			if Control(5) = '1' then
				mux_output <= "11";
			else
				  case control is 
					--when OP_NOP
					when OP_ADD  => mux_output <= "00";
					when OP_ADDU => mux_output <= "00";
					when OP_SUB	 => mux_output <= "00";
					when OP_SUBU => mux_output <= "00";
					when OP_AND	 => mux_output <= "00";
					when OP_OR	 => mux_output <= "00";
					when OP_XOR  => mux_output <= "00";
					when OP_NOR  => mux_output <= "00";
					when OP_SLL  => mux_output <= "00";
					when OP_SRL  => mux_output <= "00";
					when OP_SRA  => mux_output <= "00";
					when OP_SLA  => mux_output <= "00";
					when OP_BEQ	 => mux_output <= "00";
					when OP_BNE  => mux_output <= "00"; 
					when OP_SLT  => mux_output <= "00";
					when OP_MULT => mux_output <= "01";
					when OP_MULTU=> mux_output <= "01";
					when OP_DIV  => mux_output <= "10";
					when OP_DIVU => mux_output <= "10";
					when others  => mux_output <= mux_output;
				end case;
			end if;
		end if;
	end process;

	process(mux_output, logic_output, cout)--, mul_div_high, mul_div_low)
	variable output1, output2, debug_out : STD_LOGIC_VECTOR (31 downto 0);
	begin
	if mux_output = "00" then
		output1 := logic_output;
		output2 := logic_output;
		debug_out := (0=> cout, others=>'0');
--	elsif mux_output = "01" then
--		output1 := mul_div_low;
--		output2 := mul_div_high;
--		debug_out := (0=> cout, others=>'0');
--	elsif mux_output = "10" then
--		output1 := mul_div_high;
--		output2 := mul_div_low;
--		debug_out := (0=> cout, others=>'0');
	elsif mux_output = "11" then
		output1 := X"00000000";
		output2 := X"00000000";
		debug_out := (others=>'0');
	else
		output1 := output1;
		output2 := output1;
		debug_out := debug_out;
	end if;
	
		result1 <= output1;
		result2 <= output2;
		debug <= debug_out;
	end process;

end Behavioral;

